/******************************************************************************
 *	
 * Øving 1 UCSysDes
 *	
 *****************************************************************************/

.include "io.s"  /* include necessary constants (adresses) */

SR_GM =   16  /* statusregisterflag "GM" is bit 16 */
	
/*****************************************************************************/
/* text-segment */
/* program code is plaved here */
	
.text
	
.globl  _start
_start: /* starting point */

        /* initialize stackpointer */
        lddpc sp, stack_ptr
        
        
        /* load registers 0 and 1 once with port adresses*/
        /* and register 8 with intc adress */
        lddpc r0, pio_c_ptr
        lddpc r1, pio_b_ptr
        lddpc r8, intc
        
        /* initialize pio_c (leds)*/
        mov r2, 0xFF
        st.w r0[AVR32_PIO_PER], r2
        st.w r0[AVR32_PIO_OER], r2

        /*initialize pio_b (switches)*/
        st.w r1[AVR32_PIO_PER], r2
        st.w r1[AVR32_PIO_PUER], r2
        
        /*enable I/O-interrupt for pins corresponding to SW0 and SW2*/
        mov r2, 0b00000101
        st.w r1[AVR32_PIO_IER], r2
        com r2
        st.w r1[AVR32_PIO_IDR], r2
        
        /*setting EVBA to zero*/
        mov r2, 0x0
        mtsr 4, r2
        mov r2, input_interrupt
        st.w r8[AVR32_INTC_IPR14], r2 
        
        /*set light at LED4 (starting point)*/
        mov r3, 0x10
        st.w r0[AVR32_PIO_SODR], r3
        
        csrf SR_GM
        
loop:   /* main loop */
        rjmp loop


            /*r3 = lightPosition*/
        
/* moving light to the right */        
rightMove:
        /* dont move if light is at position one*/
        cp.w r3, 0x1
        /* return if LED0 is on */ 
        reteq sp
        /* delete old position and shift one to the right */
        st.w r0[AVR32_PIO_CODR], r3
        lsr  r3, 1
        /* set light on new position */
        st.w r0[AVR32_PIO_SODR], r3
        cp r3, 0
        retne sp

/*subroutine analog to rightMove */        
leftMove:
        cp.w r3, 0b10000000  
        reteq sp
        st.w r0[AVR32_PIO_CODR], r3
        lsl  r3, 1
        st.w r0[AVR32_PIO_SODR], r3
        cp r3 ,0
        retne sp  
              
/* interrupt routine for buttons */        
input_interrupt:
        
        /* push values of used registers onto the stack */
        st.w --sp, r4
        st.w --sp, r5
        st.w --sp, r6
        st.w --sp, r7

        /* debouncing, the value of 0xFFF is reached through testing*/
        mov r7, 0xFFF      
intr_sleep_start:
        sub r7, 1
        cp.w r7, 0
        breq intr_sleep_end
        rjmp intr_sleep_start
intr_sleep_end:
        
        /*store the last button states into memory*/
        lddpc r4, cbs_ptr
        ld.w r5, r4
        
        lddpc r6, lbs_ptr
        st.w r6, r5
        
        ld.w r6, r1[AVR32_PIO_ISR]      /*allow new interrupts*/
        ld.w r6, r1[AVR32_PIO_PDSR]     /*read state of the buttons*/
        com r6                          /*invert the button state for easier logic*/
        mov r7, 0x5                     /*0x5 includes switches 0 and 2*/ 
        and r6, r7                      /*and with mask to get relevant buttons*/
        
        st.w r4, r6             /*write current button state into memory*/

        cp.w r5, 0x0            /*is the last button state clean (all buttons are up)?*/
        brne end_int            /*if not, we should not move*/        
        
        cp.w r6, 0x1            /* is the current button pressed the right button? */
        brne else               /* if not, branch to left*/
        rcall rightMove         /* call right move*/
        rjmp end_int            /* don't update left*/
        
else:   cp.w r6, 0x4            /* is the current button pressed the left button?*/
        brne end_int            /* if not, end this routine*/
        rcall leftMove          /* call right move*/
        
        /* rebuild old registry values */        
end_int:ld.w r7, sp++
        ld.w r6, sp++
        ld.w r5, sp++
        ld.w r4, sp++
        /* return to main loop */     
        rete                    

/* pointers to some important adresses */
pio_c_ptr: /* port C */
        .int AVR32_PIOC        
pio_b_ptr: /* port B */
        .int AVR32_PIOB
intc: /* interrupt controller */
        .int AVR32_INTC
stack_ptr: /* stackpointer (symbol for linker) */ 
        .int _stack
lbs_ptr  :
        .int last_button_state
cbs_ptr  :
        .int current_button_state               
/*****************************************************************************/
/* data-segment */
/* alle dataområder som skal kunne skrives til må plasseres her */
	
.data
last_button_state:      
        .int 0
current_button_state:   
        .int 0
        